package com.ssd.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ssd.api.user.AddressApi;
import com.ssd.api.user.dto.AddressBook;
import com.ssd.entity.Gift;
import com.ssd.entity.GiftExchange;
import com.ssd.entity.PointsRecord;
import com.ssd.entity.PointsRecordTotal;
import com.ssd.entity.dto.request.GiftQueryForPageReqDTO;
import com.ssd.entity.dto.request.GiftSaveReqDTO;
import com.ssd.entity.dto.request.GiftSeizeReqDTO;
import com.ssd.entity.dto.request.GiftUpdateReqDTO;
import com.ssd.entity.dto.response.GiftPageInfoResDTO;
import com.ssd.exception.LogicException;
import com.ssd.mapper.GiftMapper;
import com.ssd.service.IGiftExchangeService;
import com.ssd.service.IGiftService;
import com.ssd.service.IPointsRecordService;
import com.ssd.service.IPointsRecordTotalService;
import com.ssd.utils.DateUtils;
import com.ssd.utils.IdUtils;
import com.ssd.utils.StringUtils;
import com.ssd.utils.UserContext;
import com.ssd.utils.redisson.annotations.Lock;
import com.ssd.view.TokenObject;
import com.ssd.viewmodel.Pager;
import com.ssd.websocket.WebSocketServer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 礼品表 服务实现类
 * </p>
 *
 * @author author
 * @since 2024-11-21
 */
@Service
@Slf4j
public class GiftServiceImpl extends ServiceImpl<GiftMapper, Gift> implements IGiftService {
    @Resource
    private IGiftExchangeService giftExchangeService;
    @Resource
    private IPointsRecordService pointsRecordService;
    @Resource
    private IPointsRecordTotalService pointsRecordTotalService;
    @Resource
    private IGiftService giftService;
    @Resource
    private RedisTemplate redisTemplate;
    @Resource
    private AddressApi addressApi;
    @Resource
    private WebSocketServer webSocketServer;
    /**
     * 保存礼品信息
     * @param giftSaveReqDTO 保存礼品请求模型
     */
    @Override
    public void save(GiftSaveReqDTO giftSaveReqDTO) {
        //获取管理人员数据
        TokenObject currentUser = UserContext.currentUser();
        //1.转换数据
        Gift gift = BeanUtil.toBean(giftSaveReqDTO, Gift.class);
        //2.设置礼品参数
        gift.setGiftId(IdUtils.getSnowflake().nextId());//礼品id
        gift.setUserId(currentUser.getUserId());//用户id
        gift.setUserPhone(currentUser.getMobile());//用户联系方式
        gift.setUserName(currentUser.getUserName());//用户名称

        //3.新增
        if (!save(gift)){
            throw new LogicException("保存礼品信息出错！");
        }
    }

    @Override
    public void update(GiftUpdateReqDTO giftUpdateReqDTO) {
        //获取管理人员数据
        Long userId = UserContext.currentUserId();
        //1.转换数据
        Gift gift = BeanUtil.toBean(giftUpdateReqDTO, Gift.class);
        //2.设置修改人
        gift.setUpdateId(userId);
        //3.修改
        if (!updateById(gift)){
            throw new LogicException("修改礼品信息失败！");
        }
    }

    @Override
    public Pager<GiftPageInfoResDTO> queryGiftForPage(GiftQueryForPageReqDTO giftQueryForPageReqDTO) {
        //1.设置分页参数
        Page<Gift> page=new Page<>(giftQueryForPageReqDTO.getPageNo(),giftQueryForPageReqDTO.getPageSize());
        //2.设置分页条件
        Page<Gift> giftPage = lambdaQuery()
                .eq(ObjectUtil.isNotNull(giftQueryForPageReqDTO.getGiftId()), Gift::getGiftId, giftQueryForPageReqDTO.getGiftId())
                .eq(ObjectUtil.isNotNull(giftQueryForPageReqDTO.getStatus()), Gift::getStatus, giftQueryForPageReqDTO.getStatus())
                .like(StringUtils.isNotEmpty(giftQueryForPageReqDTO.getGiftName()), Gift::getGiftName, giftQueryForPageReqDTO.getGiftName())
                .page(page);
        if (giftPage == null){
            return Pager.buildEmpty();
        }
        //3.查询并转换结果
        Page<GiftPageInfoResDTO> dtoPage=new Page<>();
        //分页数据
        dtoPage.setRecords(BeanUtil.copyToList(giftPage.getRecords(), GiftPageInfoResDTO.class));
        //当前页码
        dtoPage.setCurrent(giftPage.getCurrent());
        //每页条数
        dtoPage.setSize(giftPage.getSize());
        //总数据数量
        dtoPage.setTotal(giftPage.getTotal());

        return Pager.build(dtoPage);
    }

    @Override
    public List<GiftPageInfoResDTO> queryGiftConsumerForPage(Long lastId) {
        //1.设置查询条件
        List<Gift> gifts = lambdaQuery()
                .eq(Gift::getStatus, 1)
                .le(ObjectUtil.isNotNull(lastId), Gift::getGiftId, lastId)
                .orderByDesc(Gift::getGiftId)
                .select(Gift::getGiftId)
                .last(" limit 10")
                .list();
        if (CollUtil.isEmpty(gifts)){
            return new ArrayList<>();
        }
        //2.取出id集合
        List<Long> longs = gifts.stream().map(Gift::getGiftId).collect(Collectors.toList());
        //3.查询
        List<Gift> giftList = baseMapper.selectBatchIds(longs);
        //4.转换
        return BeanUtil.copyToList(giftList, GiftPageInfoResDTO.class);
    }

    @Override
    public void seizeGift(GiftSeizeReqDTO giftSeizeReqDTO) throws IOException {
        //1.获取当前登录用户信息
        TokenObject currentUser = UserContext.currentUser();
        //2.查询礼品信息
        Gift gift = getById(giftSeizeReqDTO.getGiftId());
        if (ObjectUtil.isNull(gift)){
            throw new LogicException("礼品不存在！");
        }
        //检查库存和礼品状态
        if (!gift.getStatus().equals(1) || gift.getStock() <= 0){
            throw new LogicException("该礼品兑换不了！");
        }
        //3.查询用户积分余额
        PointsRecordTotal pointsRecordTotal = pointsRecordTotalService.lambdaQuery()
                .eq(PointsRecordTotal::getUserId, currentUser.getUserId())
                .one();
        if (ObjectUtil.isNull(pointsRecordTotal) || pointsRecordTotal.getPoints() < gift.getRequiredPoints() ){
            throw new LogicException("用户积分余额不足！");
        }

        //4.用户积分兑换礼品：使用redisson分布式锁
        giftService.redissonGift(gift,pointsRecordTotal,giftSeizeReqDTO.getAddressId(),currentUser.getUserId());
        //5.发送兑换记录给前端

        // 构造一个包含 user 和 shop 的简单JSON对象
        Map<String, String> message = new HashMap<>();
        message.put("user", currentUser.getUserName());
        message.put("shop", gift.getGiftName());

        // 将 Map 转换为 JSON 字符串
        String jsonString = new ObjectMapper().writeValueAsString(message);

        // 使用 webSocketServer 发送消息给所有客户端
        webSocketServer.sendMessageToAll(jsonString);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    @Lock(name = "lock:gift:{gift.giftId}")
    public void redissonGift(Gift gift, PointsRecordTotal recordTotal, Long addressId, Long userId) {
        //1.礼品减库存
        boolean update = lambdaUpdate()
                .eq(Gift::getGiftId, gift.getGiftId())
                .eq(Gift::getStatus, 1)
                .gt(Gift::getStock, 0)
                .set(Gift::getStock, gift.getStock() - 1)
                .set(Gift::getSales, gift.getSales() + 1)
                .update();
        if (!update){
            throw new LogicException("兑换礼品失败！");
        }
        //2.用户减积分
        int points = recordTotal.getPoints() - gift.getRequiredPoints();
        boolean update1 = pointsRecordTotalService.lambdaUpdate()
                .eq(PointsRecordTotal::getUserId, userId)
                .eq(PointsRecordTotal::getId, recordTotal.getId())
                .ge(PointsRecordTotal::getPoints, gift.getRequiredPoints())
                .set(PointsRecordTotal::getPoints, points)
                .update();
        if (!update1){
            throw new LogicException("兑换礼品失败！");
        }
        //3.远程调用地址服务
//        AddressBook address = addressApi.getAddress(addressId);
//        if (ObjectUtil.isNull(address)){
//            throw new LogicException("收货地址不存在！");
//        }
        AddressBook address = new AddressBook();
        address.setId(1L);
        address.setName("张三");
        address.setPhone("13800000000");
        address.setAddress("北京市昌平区回龙观");
        //4.生成礼品兑换记录
        GiftExchange giftExchange = GiftExchange.builder()
                .id(generatorPointsRecordId())//兑换id
                .giftId(gift.getGiftId())//礼品id
                .giftName(gift.getGiftName())//礼品名称
                .giftImage(gift.getGiftImage())//礼品图片
                .userId(userId)//用户id
                .addressId(address.getId())//地址id
                .receiverName(address.getName())//收货人名字
                .receiverPhone(address.getPhone())//收货人电话
                .addressDetail(address.getAddress())//详细地址
                .status(1)//状态：1 待发货，2 发货中，3 已完成
                .build();
        if (!giftExchangeService.save(giftExchange)){
            throw new LogicException("兑换礼品失败！");
        }
        //5.生成积分兑换记录
        PointsRecord pointsRecord = PointsRecord.builder()
                .id(pointsRecordTotalService.generatorPointsRecordId())//积分记录表id
                .userId(userId)//用户id
                .points(points)//积分值
                .type(2)//积分方式：1-收入，2-使用
                .giftId(gift.getGiftId())//兑换礼品id
                .remark("兑换礼品")//备注
                .build();
        if (!pointsRecordService.save(pointsRecord)){
            throw new LogicException("兑换礼品失败！");
        }
    }

    /**
     * 生成积分记录id 格式：{yyMMdd}{13位id} TODO
     * @return
     */
    public   Long generatorPointsRecordId() {
        //通过Redis自增序列得到序号
        Long id = redisTemplate.opsForValue().increment("giftExchange:page_key:generator", 1);
        long pointsRecordId = DateUtils.getFormatDate(LocalDateTime.now(), "yyMMdd") * 10000000000000L + id;
        return pointsRecordId;
    }

}
